/**
 * @typedef {import('mdast').Root} Root
 * @typedef {import('hast-util-sanitize').Schema} Schema
 *
 * @typedef ExtraOptionsFields
 *   Configuration (optional).
 * @property {boolean|Schema|null} [sanitize]
 *   How to sanitize the output.
 * @property {import('mdast-util-to-hast').Handlers} [handlers={}]
 *   Object mapping mdast nodes to functions handling them.
 *
 * @typedef {import('hast-util-to-html').Options & ExtraOptionsFields} Options
 */

import { toHtml } from 'hast-util-to-html'
import { sanitize } from 'hast-util-sanitize'
import { toHast } from 'mdast-util-to-hast'

/**
 * Plugin to serialize markdown as HTML.
 *
 * @type {import('unified').Plugin<[Options?]|void[], Root, string>}
 */
export default function remarkHtml(settings = {}) {
  const options = { ...settings }
  /** @type {boolean|undefined} */
  let clean

  if (typeof options.sanitize === 'boolean') {
    clean = options.sanitize
    options.sanitize = undefined
  }

  if (typeof clean !== 'boolean') {
    clean = true
  }

  Object.assign(this, { Compiler: compiler })

  /**
   * @type {import('unified').CompilerFunction<Root, string>}
   */
  function compiler(node, file) {
    const hast = toHast(node, {
      allowDangerousHtml: !clean,
      handlers: options.handlers
    })
    // @ts-expect-error: assume root.

    const cleanHast = clean ? sanitize(hast, options.sanitize) : hast

    /* -- 业务处理代码 start -- */
    
    // 移除所有空行
    let targetHast = removeBl(cleanHast.children)
    function removeBl(list) {
      return list.filter(item => {
        if (item.children) {
          item.children = removeBl(item.children)
        }
        return !(item.type === 'text' && item.value === '\n')
      })
    }

    // 增加菜单样式类
    if (targetHast) {
      targetHast = targetHast.find(item => {
        // 处理第一层，找到ul，增加 top
        if (item.tagName === 'ul') {
          if (!item.properties) {
            item.properties = {}
          }
          item.properties.className = 'top'
          return true;
        }
        return false;
      });
    }

    // 增加菜单展开收起类
    checkFoldLi(targetHast, 2)

    function checkFoldLi(list, idx) {
      Array.from(list.children).forEach(n => {
        // 获取ul类型的子节点
        const ulNode = n.children.find(a => a.tagName === 'ul')
        // 特殊处理第二层, 为不可展开的菜单增加 has-no-subject
        if (n.tagName === 'li' && !ulNode && idx === 2) {
          if (!n.properties) {
            n.properties = {}
          }
          n.properties.className = 'has-no-subject'
        }
        // 为所有可展开的菜单增加 can-unfold, folded
        if (ulNode) {
          if (!n.properties) {
            n.properties = {}
          }
          n.properties.className = 'can-unfold folded'
          checkFoldLi(ulNode)
          // 特殊处理第三层及以后，如果可展开增加+小图片
          if (!idx) {
            n.children.push({
              type: 'element',
              tagName: 'span',
              properties: { className: 'small-folded-icon' }
            })
          }
        }
        // 替换a标签href
        const linkNode = n.children.find(a => a.tagName === 'a')
        if (linkNode && linkNode.properties && linkNode.properties.href.includes('.md')) {
          const href = linkNode.properties.href
          const fileName = href.substr(href.lastIndexOf('/') + 1, href.length).replace('.md', '')
          const realHref = options.tocLinkPrefix + fileName
          linkNode.properties.href = realHref
          if (options.slug === realHref) {
            linkNode.properties.className = 'is-active'
          } else {
            linkNode.properties.className = ''
          }
        }
      })
    }

    function findTargetMenu(obj) {
      const stack = [];
      let did = false;
      function walk(o, index) {
        if (o.properties && o.properties.className === 'is-active') {
          did = true;
          stack.push(o);
        } else if (o.children) {
          if (did) {
            return;
          }
          stack.push(o);
          o.children.forEach(item => {
            if (!did) {
              walk(item, index + 1);
            }
          });
          if (stack.length === index) {
            stack.pop();
          }
        }
      }
      walk(obj, 1);
      return stack;
    }

    const astNodes = findTargetMenu(targetHast)
    astNodes.forEach(n => {
      if (n.properties && n.properties.className && n.properties.className.indexOf('can-unfold') > -1) {
        n.properties.className = 'can-unfold'
      }
    })

    /* -- 业务处理代码 end -- */

    const result = toHtml(
      // @ts-expect-error: assume root.
      targetHast,
      Object.assign({}, options, { allowDangerousHtml: !clean })
    )

    if (file.extname) {
      file.extname = '.html'
    }

    // Add an eof eol.
    return node &&
      node.type &&
      node.type === 'root' &&
      result &&
      /[^\r\n]/.test(result.charAt(result.length - 1))
      ? result + '\n'
      : result
  }
}
